cnodejs.org 网站首页分析

众所周知,在网站建设这条康庄大道上,从前端架构到后端、服务器的架构,有许多的解决方案,各种高新技术更是层出不穷。本文将以一个网站的前端为入口,从前端层、后端层到服务器层,分析网站的架构、前后端技术栈以及网站的优化技术,管中窥豹,来认识这条大道~

1. 服务器层面:

1. 支撑架构(Nginx、IIS、Apache):

1
Server: nginx/1.4.6 (Ubuntu)

由Response Header 中Server字段可知,服务器使用的是Ubuntu系统,服务器是Nginx/1.4.6 .

2. 数据库

3. 服务器优化:

1. HSTS头部:

当用户使用http访问时,会返回一个302重定向,重定向到https的地址,后续访问都由https传输,而由于302重定向容易被篡改,这样的通信模式存在一定的风险。

1
Strict-Transport-Security:max-age=15768000
  • 由Response Header 中Strict-Transport-Security 字段可知,服务器端开启了Strict-Transport-Security功能,其作用是作用是强制客户端(如浏览器)使用HTTPS与服务器创建连接。
  • HSTS可以很大程度上解决SSL剥离攻击,因为只要浏览器曾经与服务器创建过一次安全连接,之后浏览器会强制使用HTTPS,即使链接被换成了HTTP,另外,如果中间人使用自己的自签名证书来进行攻击,浏览器会给出警告,但是许多用户会忽略警告。HSTS解决了这一问题,一旦服务器发送了HSTS字段,用户将不再允许忽略警告.

2.后端技术架构:

1. 同构/异构:

2. 语言、框架:

1
X-Powered-By: Express(Nodejs)

由Response Header 中X-Powered-By 字段可得知,服务器语言使用的是Node.js ,使用的框架是Express .

3. 鉴权、前后端API:

4. 后端优化:

1. 服务端压缩:
1
Content-Encoding:gzip
  • 由Response Header 中Content-Encoding字段可得知服务器使用的是gzip文本压缩格式.
  • 浏览器发送请求时,通过 Accept-Encoding 带上自己支持的内容编码格式列表;服务端从中挑选一种用来对正文进行编码,并通过 Content-Encoding 响应头指明选定的格式;浏览器拿到响应正文后,依据 Content-Encoding 进行解压。
2. HTTP缓存控制:
1
2
Cache-control:public, max-age=7200
ETag:W/"c95b-1Lg4JB+MjVViSanrBU0LRg"

由Response Header 中Cache-control字段可知,访问当前页面后的2h内再次访问,将不会去访问服务器,而去访问缓存。而由ETag字段可知,当cache过期时,浏览器再次请求时要发If-None-Match的请求。CGI据此可以知道这个请求的客户端是否有cache,此时如果 CGI联系server失败,那么可以直接返回304,驱使客户端使用上一次cache的正确结果,且更新保鲜期max-age为7200秒,这样我们实现了一个基于HTTP cache的容错.

  • Expires策略:Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。不过Expires 是HTTP 1.0的东西,现在默认浏览器均默认使用HTTP 1.1,所以它的作用基本忽略。Expires 的一个缺点就是,返回的到期时间是服务器端的时间,这样存在一个问题,如果客户端的时间与服务器的时间相差很大(比如时钟不同步,或者跨时区),那么误差就很大,所以在HTTP 1.1版开始,使用Cache-Control: max-age=秒替代。
  • Cache-control策略:Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires
  • Last-Modified:标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。

    If-Modified-Since:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Last-Modified声明,则再次向web服务器请求时带上头 If-Modified-Since,表示请求时间。web服务器收到请求后发现有头If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源又被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的cache。
  • Etag:web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定)。Apache中,ETag的值,默认是对文件的索引节(INode),大小(Size)和最后修改时间(MTime)进行Hash后得到的。

    If-None-Match:当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务器请求时带上头If-None-Match (Etag的值)。web服务器收到请求后发现有头If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。
  • Last-Modified标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间,如果某些文件会被定期生成,当有时内容并没有任何变化,但Last-Modified却改变了,导致文件没法使用缓存,有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形.Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。Last-Modified与ETag一起使用时,服务器会优先验证ETag。
3. CSRF防护:
1
2
<meta content="_csrf" name="csrf-param">
<meta content="6eEHcEur-Q-CoC0eMc3GIRofusFMhD6fYr4Y" name="csrf-token">

分析首页html代码可知:服务端做了CSRF防护,由服务端生成crsf-token,每次请求都将和服务端的进行对比。

csrf 防护策略:

  • 通过 referer、token 或者 验证码 来检测用户提交。
  • 尽量不要在页面的链接中暴露用户隐私信息。
  • 对于用户修改删除等操作最好都使用post 操作 。
  • 避免全站通用的cookie,严格设置cookie的域

3.前端技术栈:

1. 框架:

2. 工具:

3. 库:

1
<link rel="stylesheet" href="//o4j806krb.qnssl.com/public/stylesheets/index.min.9d1ebdbb.min.css" media="all" />

由首页中引入标签可知,首页引进了Bootstrap/v2.3.1 框架,并使用了cdn资源优化。

4. 标准化(代码、常见优化点、模块化):

1. CDN优化:
  • 文件资源:
1
<link rel="stylesheet" href="//o4j806krb.qnssl.com/public/stylesheets/index.min.9d1ebdbb.min.css" media="all" />
  • 图片资源:
1
<img src="//dn-cnode.qbox.me/Fn4D6BhOTz1IswvmzeZ1q7QW1ls_">

由上述首页代码可知,网站资源引入采用了cdn优化,有dn-cnode.qbox.me和o4j806krb.qnssl.com等cdn服务站。

CDN(Content Delivery Network)内容分发网络:通过在现有的Internet中增加一层新的网络架构,部署边缘服务器,将网站的内容发布到最接近用户的Cache服务器,使用户可以就近取得所需的内容,实现用户就近访问,有效提升网站的访问效果、安全性和稳定性。

2. RSS优化:
1
<link title="RSS" type="application/rss+xml" rel="alternate" href="/rss"/>

由上述首页标签可知,本站首页内部加入了RSS源。有以下好处:

  1. 搜索引擎会认为有rss源的网站有更好的用户体验。
  2. 订阅该网站的用户会第一时间看到网站更新的内容。
  3. 配合百度的ping功能使用,RSS数据提交给搜索引擎后,能加快搜索引擎收录与信息的推广。
  • RSS:在线共享内容的一种简易方式(也叫聚合内容,全称Really Simple Syndication)。使用RSS订阅能更快地速获取信息和获取网站内容的最新更新。更直白的说,你可以不用再一一打开各个网站页面,而是通过阅读器一次一起阅读所有你订阅了的网站的最新内容。
3. 分块编码:
1
Transfer-Encoding:chunked

由Response Header 中Transfer-Encoding字段可得知,网站采用了分块传输编码.

  • Transfer-Encoding的作用:对于非持久连接,浏览器可以通过连接是否关闭来界定请求或响应实体的边界;而对于持久连接,这种方法显然不奏效.要解决上面这个问题,最容易想到的办法就是计算实体长度,并通过头部告诉对方。这就要用到 Content-Length 了,通常如果 Content-Length 比实际长度短,会造成内容被截断;如果比实体内容长,会造成 pending.服务端为了计算响应实体长度而缓存所有内容,跟更短的 TTFB 理念背道而驰。但在 HTTP 报文中,实体一定要在头部之后,顺序不能颠倒,为此我们需要一个新的机制:不依赖头部的长度信息,也能知道实体的边界.Transfer-Encoding 正是用来解决上面这个问题的. 历史上 Transfer-Encoding 可以有多种取值,为此还引入了一个名为 TE 的头部用来协商采用何种传输编码。但是最新的 HTTP 规范里,只定义了一种传输编码:分块编码(chunked). 在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF。最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束.通过这种简单的分块策略,很好的解决了前面提出的问题.

  • Transfer-Encoding: identity ?

5. 前端工程化:

1
https://o4j806krb.qnssl.com/public/index.min.aeb155e1.min.js

由此文件可知,js文件经过了压缩,混淆操作。

-------------本文结束感谢您的阅读-------------